inspector: Make the recorder node list use a ListView
authorBenjamin Otte <otte@redhat.com>
Mon, 14 Oct 2019 04:50:40 +0000 (06:50 +0200)
committerMatthias Clasen <mclasen@redhat.com>
Sat, 30 May 2020 23:26:45 +0000 (19:26 -0400)
It's quite a bit faster now, but the code is also a bit more awkward.

Pain points:

- GtkTreeListModel cannot be created in UI files because it needs
  a CreateModelFunc.
  Using a signal for this doesn't work because autoexpand wants to
  expand the model before the signal handler is connected.

- The list item factory usage is still awkward. It's bearable here
  because the list items are very simple, but still.

gtk/gtktreeexpander.c
gtk/inspector/recorder.c
gtk/inspector/recorder.ui

index 7dcd67ad275cd491b750e12e6c33b69582d2f282..71be20b1b8327f775e9fdc9a8102dad4323d5ba1 100644 (file)
@@ -186,6 +186,7 @@ gtk_tree_expander_clear_list_row (GtkTreeExpander *self)
     return;
 
   g_signal_handler_disconnect (self->list_row, self->notify_handler);
+  self->notify_handler = 0;
   g_clear_object (&self->list_row);
 }
 
index acd82a1613a7a1f0c85af873cc147113231a50a8..9b77699d01101a38a7689d618292aea13d8c9778 100644 (file)
 #include <gtk/gtkbinlayout.h>
 #include <gtk/gtkbox.h>
 #include <gtk/gtkfilechooserdialog.h>
+#include <gtk/gtkfunctionslistitemfactory.h>
 #include <gtk/gtklabel.h>
 #include <gtk/gtklistbox.h>
+#include <gtk/gtklistview.h>
 #include <gtk/gtkmessagedialog.h>
 #include <gtk/gtkpicture.h>
 #include <gtk/gtkpopover.h>
+#include <gtk/gtksingleselection.h>
 #include <gtk/gtktogglebutton.h>
 #include <gtk/gtktreeexpander.h>
 #include <gtk/gtktreelistmodel.h>
@@ -51,6 +54,8 @@ struct _GtkInspectorRecorderPrivate
 {
   GListModel *recordings;
   GtkTreeListModel *render_node_model;
+  GListStore *render_node_root_model;
+  GtkSingleSelection *render_node_selection;
 
   GtkWidget *recordings_list;
   GtkWidget *render_node_view;
@@ -295,40 +300,58 @@ node_name (GskRenderNode *node)
     }
 }
 
-static GtkWidget *
-create_widget_for_render_node (gpointer row_item,
-                               gpointer unused)
+static void
+setup_widget_for_render_node (GtkListItem *list_item,
+                              gpointer     unused)
+{
+  GtkWidget *expander, *box, *child;
+
+  /* expander */
+  expander = gtk_tree_expander_new ();
+  gtk_list_item_set_child (list_item, expander);
+
+  box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3);
+  gtk_tree_expander_set_child (GTK_TREE_EXPANDER (expander), box);
+
+  /* icon */
+  child = gtk_image_new ();
+  gtk_box_append (GTK_BOX (box), child);
+
+  /* name */
+  child = gtk_label_new (NULL);
+  gtk_box_append (GTK_BOX (box), child);
+}
+
+static void
+bind_widget_for_render_node (GtkListItem *list_item,
+                             gpointer     unused)
 {
   GdkPaintable *paintable;
   GskRenderNode *node;
-  GtkWidget *row, *expander, *box, *child;
+  GtkTreeListRow *row_item;
+  GtkWidget *expander, *box, *child;
   char *name;
 
+  row_item = gtk_list_item_get_item (list_item);
   paintable = gtk_tree_list_row_get_item (row_item);
   node = gtk_render_node_paintable_get_render_node (GTK_RENDER_NODE_PAINTABLE (paintable));
-  row = gtk_list_box_row_new ();
 
   /* expander */
-  expander = gtk_tree_expander_new ();
+  expander = gtk_list_item_get_child (list_item);
   gtk_tree_expander_set_list_row (GTK_TREE_EXPANDER (expander), row_item);
-  gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), expander);
-
-  box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3);
-  gtk_tree_expander_set_child (GTK_TREE_EXPANDER (expander), box);
+  box = gtk_tree_expander_get_child (GTK_TREE_EXPANDER (expander));
 
   /* icon */
-  child = gtk_image_new_from_paintable (paintable);
-  gtk_box_append (GTK_BOX (box), child);
+  child = gtk_widget_get_first_child (box);
+  gtk_image_set_from_paintable (GTK_IMAGE (child), paintable);
 
   /* name */
   name = node_name (node);
-  child = gtk_label_new (name);
+  child = gtk_widget_get_last_child (box);
+  gtk_label_set_label (GTK_LABEL (child), name);
   g_free (name);
-  gtk_box_append (GTK_BOX (box), child);
 
   g_object_unref (paintable);
-
-  return row;
 }
 
 static void
@@ -344,11 +367,8 @@ recordings_list_row_selected (GtkListBox           *box,
   else
     recording = NULL;
 
-  g_clear_object (&priv->render_node_model);
-
   if (GTK_INSPECTOR_IS_RENDER_RECORDING (recording))
     {
-      GListStore *root_model;
       graphene_rect_t bounds;
       GskRenderNode *node;
       GdkPaintable *paintable;
@@ -358,14 +378,10 @@ recordings_list_row_selected (GtkListBox           *box,
       paintable = gtk_render_node_paintable_new (node, &bounds);
       gtk_picture_set_paintable (GTK_PICTURE (priv->render_node_view), paintable);
 
-      root_model = g_list_store_new (GDK_TYPE_PAINTABLE);
-      g_list_store_append (root_model, paintable);
-      priv->render_node_model = gtk_tree_list_model_new (FALSE,
-                                                         G_LIST_MODEL (root_model),
-                                                         TRUE,
-                                                         create_list_model_for_render_node_paintable,
-                                                         NULL, NULL);
-      g_object_unref (root_model);
+      g_list_store_splice (priv->render_node_root_model,
+                           0, g_list_model_get_n_items (G_LIST_MODEL (priv->render_node_root_model)),
+                           (gpointer[1]) { paintable },
+                           1);
       g_object_unref (paintable);
 
       g_print ("%u render nodes\n", g_list_model_get_n_items (G_LIST_MODEL (priv->render_node_model)));
@@ -373,14 +389,9 @@ recordings_list_row_selected (GtkListBox           *box,
   else
     {
       gtk_picture_set_paintable (GTK_PICTURE (priv->render_node_view), NULL);
+      g_list_store_remove_all (priv->render_node_root_model);
     }
 
-
-  gtk_list_box_bind_model (GTK_LIST_BOX (priv->render_node_list),
-                           G_LIST_MODEL (priv->render_node_model),
-                           create_widget_for_render_node,
-                           NULL, NULL);
-
   if (recording)
     g_object_unref (recording);
 }
@@ -897,20 +908,16 @@ get_selected_node (GtkInspectorRecorder *recorder)
 {
   GtkInspectorRecorderPrivate *priv = gtk_inspector_recorder_get_instance_private (recorder);
   GtkTreeListRow *row_item;
-  GtkListBoxRow *row;
   GdkPaintable *paintable;
   GskRenderNode *node;
 
-  row = gtk_list_box_get_selected_row (GTK_LIST_BOX (priv->render_node_list));
-  if (row == NULL)
+  row_item = gtk_single_selection_get_selected_item (priv->render_node_selection);
+  if (row_item == NULL)
     return NULL;
 
-  row_item = g_list_model_get_item (G_LIST_MODEL (priv->render_node_model),
-                                    gtk_list_box_row_get_index (row));
   paintable = gtk_tree_list_row_get_item (row_item);
   node = gtk_render_node_paintable_get_render_node (GTK_RENDER_NODE_PAINTABLE (paintable));
   g_object_unref (paintable);
-  g_object_unref (row_item);
 
   return node;
 }
@@ -925,14 +932,10 @@ render_node_list_selection_changed (GtkListBox           *list,
   GdkPaintable *paintable;
   GtkTreeListRow *row_item;
 
-  if (row == NULL)
-    {
-      gtk_widget_set_sensitive (priv->render_node_save_button, FALSE);
-      return;
-    }
+  row_item = gtk_single_selection_get_selected_item (priv->render_node_selection);
+  if (row_item == NULL)
+    return;
 
-  row_item = g_list_model_get_item (G_LIST_MODEL (priv->render_node_model),
-                                    gtk_list_box_row_get_index (row));
   paintable = gtk_tree_list_row_get_item (row_item);
 
   gtk_widget_set_sensitive (priv->render_node_save_button, TRUE);
@@ -941,7 +944,6 @@ render_node_list_selection_changed (GtkListBox           *list,
   populate_render_node_properties (GTK_LIST_STORE (priv->render_node_properties), node);
 
   g_object_unref (paintable);
-  g_object_unref (row_item);
 }
 
 static void
@@ -1217,6 +1219,8 @@ gtk_inspector_recorder_dispose (GObject *object)
   GtkInspectorRecorderPrivate *priv = gtk_inspector_recorder_get_instance_private (recorder);
 
   g_clear_object (&priv->render_node_model);
+  g_clear_object (&priv->render_node_root_model);
+  g_clear_object (&priv->render_node_selection);
 
   G_OBJECT_CLASS (gtk_inspector_recorder_parent_class)->dispose (object);
 }
@@ -1257,7 +1261,6 @@ gtk_inspector_recorder_class_init (GtkInspectorRecorderClass *klass)
 
   gtk_widget_class_bind_template_callback (widget_class, recordings_clear_all);
   gtk_widget_class_bind_template_callback (widget_class, recordings_list_row_selected);
-  gtk_widget_class_bind_template_callback (widget_class, render_node_list_selection_changed);
   gtk_widget_class_bind_template_callback (widget_class, render_node_save);
   gtk_widget_class_bind_template_callback (widget_class, node_property_activated);
 
@@ -1268,6 +1271,7 @@ static void
 gtk_inspector_recorder_init (GtkInspectorRecorder *recorder)
 {
   GtkInspectorRecorderPrivate *priv = gtk_inspector_recorder_get_instance_private (recorder);
+  GtkListItemFactory *factory;
 
   gtk_widget_init_template (GTK_WIDGET (recorder));
 
@@ -1277,6 +1281,23 @@ gtk_inspector_recorder_init (GtkInspectorRecorder *recorder)
                            recorder,
                            NULL);
 
+  priv->render_node_root_model = g_list_store_new (GDK_TYPE_PAINTABLE);
+  priv->render_node_model = gtk_tree_list_model_new (FALSE,
+                                                     G_LIST_MODEL (priv->render_node_root_model),
+                                                     TRUE,
+                                                     create_list_model_for_render_node_paintable,
+                                                     NULL, NULL);
+  priv->render_node_selection = gtk_single_selection_new (G_LIST_MODEL (priv->render_node_model));
+  g_signal_connect (priv->render_node_selection, "notify::selected-item", G_CALLBACK (render_node_list_selection_changed), recorder);
+
+  factory = gtk_functions_list_item_factory_new (setup_widget_for_render_node,
+                                                 bind_widget_for_render_node,
+                                                 NULL, NULL);
+  gtk_list_view_set_factory (GTK_LIST_VIEW (priv->render_node_list), factory);
+  g_object_unref (factory);
+  gtk_list_view_set_model (GTK_LIST_VIEW (priv->render_node_list),
+                           G_LIST_MODEL (priv->render_node_selection));
+
   priv->render_node_properties = GTK_TREE_MODEL (gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, GDK_TYPE_TEXTURE));
   gtk_tree_view_set_model (GTK_TREE_VIEW (priv->node_property_tree), priv->render_node_properties);
   g_object_unref (priv->render_node_properties);
index 364a4acac5b1376bfc157e2daf6792aebd1dd7dd..100d51659b1dacfa9222dca6107112b984d45645 100644 (file)
@@ -79,9 +79,9 @@
                   <class name="sidebar"/>
                 </style>
                 <child>
-                  <object class="GtkListBox" id="render_node_list">
+                  <object class="GtkListView" id="render_node_list">
                     <property name="vexpand">1</property>
-                    <signal name="row-selected" handler="render_node_list_selection_changed"/>
+                    <property name="hexpand">1</property>
                   </object>
                 </child>
               </object>